#pragma once
#include <iostream>
#include <cstring>
#include <cerrno>
#include <memory>
#include <vector>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;

const string SEM_KEY_PATH = "/tmp";
const int SEM_KEY_ID = 0x6666;
const int SEM_NUM = 1;
#define SEM_FLAG_BUID (IPC_EXCL | IPC_CREAT)
#define SEM_FLAG_GET IPC_CREAT
// 产品类：信号量集
class Semaphore
{
public:
    Semaphore(int semid, int flag) : _semid(semid), _flag(flag)
    {
    }
    ~Semaphore()
    {
        if (_semid >= 0 && _flag == SEM_FLAG_BUID)
        {
           // cout<<"第"<<i++<<"次析构函数"<<endl;
            // 先检查信号量是否还存在
            struct semid_ds buf;
            if (semctl(_semid, 0, IPC_STAT, &buf) == -1)
            {
                if (errno == EINVAL)
                {
                    cout << "信号量 " << _semid << " 已被删除" << endl;
                    return;
                }
            }

            cout << "进程id " << getpid() << " 删除信号量 " << _semid << endl;
            if (semctl(_semid, 0, IPC_RMID) == -1)
            {
                // 忽略已经删除的信号量的错误
                if (errno != EINVAL)
                {
                    cerr << "semctl IPC_RMID error: "
                         << strerror(errno) << " (semid: " << _semid << ")" << endl;
                }
            }
        }
    }
    void PV(int who, int op)
    {
        struct sembuf sb;
        sb.sem_num = who;      // 操作第who个信号量
        sb.sem_op = op;        // 操作数
        sb.sem_flg = SEM_UNDO; // 操作标志
        // cout<<"sem_op = " << sb.sem_op << endl;
        if (semop(_semid, &sb, 1) == -1)
        {
            cerr << "semop error: " << strerror(errno) << endl;
        }
        // cout<<"semop success!"<<endl;
    }
    void P(int who) // Wait operation
    {
        PV(who, -1);
    }
    void V(int who)
    {
        PV(who, 1);
    }

    int getSemid() const
    {
        return _semid;
    }

private:
    int _semid;
    int _flag;
};

// 抽象建造者
class SemaphoreBuilder
{
public:
    virtual ~SemaphoreBuilder() = default;
    virtual void buildKey() = 0;
    virtual void buildNum(int num) = 0;
    virtual void buildPermissions(int per) = 0;
    virtual void buildSetVal(const std::vector<int> &val) = 0;
    virtual void build(int flag) = 0;
    virtual void initSemaphore() = 0;
    virtual std::shared_ptr<Semaphore> getSemaphore() = 0;
};

// 具体建造者：sistem V信号量建造者
class ConstructBuilder : public SemaphoreBuilder
{
public:
    virtual void buildKey() override
    {
        // 实现构建key的逻辑
        _key = ftok(SEM_KEY_PATH.c_str(), SEM_KEY_ID);
        if (_key == -1)
        {
            cerr << "ftok error" << endl;
        }
    }
    virtual void buildNum(int num) override
    {
        _num = num;
    }
    virtual void buildPermissions(int per) override
    {
        _permissions = per;
    }
    virtual void buildSetVal(const std::vector<int> &val) override
    {
        _setVal = val;
    }
    virtual void build(int flag) override
    {
        // 实现构建信号量的逻辑
        int semid = semget(_key, _num, flag | _permissions);
        if (semid == -1)
        {
            cerr << "semget error" << endl;
            _semaphore = nullptr;
            return;
        }
        cout << "semid = " << semid << endl;
        _semaphore = std::make_shared<Semaphore>(semid, flag);
    }
    virtual void initSemaphore() override
    {
        if (_num > 0 && _setVal.size() == _num)
        {
            for (int i = 0; i < _num; i++)
            {
                init(_semaphore->getSemid(), i, _setVal[i]);
            }
        }
    }
    virtual std::shared_ptr<Semaphore> getSemaphore() override
    {
        return _semaphore;
    }

private:
    void init(int semid, int num, int val)
    {
        union semun
        {
            int val;               // Value for SETVAL
            struct semid_ds *buf;  // Buffer for IPC_STAT, IPC_SET
            unsigned short *array; // Array for GETALL, SETALL
            struct seminfo *__buf; // Buffer for IPC_INFO
        } su;
        su.val = val; // Initialize semaphore to specified value
        if (semctl(semid, num, SETVAL, su) == -1)
        {
            cerr << "semctl error for semaphore " << num
                 << ": " << strerror(errno) << endl;
        }
    }

private:
    key_t _key;
    int _num;
    int _permissions;
    std::vector<int> _setVal;
    std::shared_ptr<Semaphore> _semaphore;
};

// 指挥者
class Director
{
public:
    void construct(std::shared_ptr<SemaphoreBuilder>& builder, int flag, int num = 1, int per = 0666, const std::vector<int> &val = {1})
    {
        builder->buildKey();
        builder->buildNum(num);
        builder->buildPermissions(per);
        builder->buildSetVal(val);
        builder->build(flag);
        if (flag == SEM_FLAG_BUID)
        {
            builder->initSemaphore();
        }
    }
};
